package testing;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Random;

import com.thesis.algorithm.Device;
import com.thesis.algorithm.FileConverter;
import com.thesis.algorithm.Sequence;
import com.thesis.algorithm.SequenceElement;
import com.thesis.algorithm.SequenceMatching;
import com.thesis.utils.BusControl;
import com.thesis.utils.CONSTANTS;
import com.thesis.utils.Utils;
import com.thesis.utils.VelocityEstimate;
import com.thesis.utils.VelocityEstimateTest;
import com.thesis.utils.hVelocityEstimate;

public class VelocityEstimateWrapper {
    int ESTI_LENGTH;
	LinkedList<Sequence> _TESTDATA = new LinkedList<Sequence>();
	SequenceMatching sm = new SequenceMatching(SequenceMatching.MODE_READ_FROM_BINARYFILE);
	BusControl busController = new BusControl();
	VelocityEstimate ve;
	FileConverter fc = new FileConverter(CONSTANTS.TEST_DATA_FOLDER);
	public VelocityEstimateWrapper() {
		// TODO Auto-generated constructor stub
		
		_TESTDATA = busController.produceTrainSequence(fc.listOfDevices);
		for (int i = 0; i < _TESTDATA.size(); i++) {
			System.out.println("TESTDATA" + _TESTDATA.get(i).BusRouteID + " " + _TESTDATA.get(i).size());
		}
	}

	public void testBusStopAndPrintToFile(int sequence_length,
			Writer outSummary, int consider_length, Writer outExcel) {
                    ESTI_LENGTH = consider_length;
            double SumDiffAll = 0;
            int allcount = 0;
            double allMax = 0;
            double allMin = 5000;
            double SumDiffSteps = 0;
            int stepcount = 0;
            double stepMax = 0;
            double stepMin = 5000;
            double GPSv = 0;
            double finalsteps = 0;
            double all = 0;

		try {
			Writer out = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(CONSTANTS.RESULT_FOLDER
							+ "velocityEstimate_sequenceLength"
							+ sequence_length + "T" + consider_length + ".txt"), "UTF-8"));
                        Writer out2 = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(CONSTANTS.RESULT_FOLDER
							+ "velocityestimate_printout"
							+ sequence_length + "T" + consider_length + ".txt"), "UTF-8"));
                        out2.write("GPSv\tall\tfinalsteps\tMath.abs(GPSv - all)\tMath.abs(GPSv - finalsteps)\n");
			Random randomGenerator = new Random();
			
			LinkedList <VelocityEstimateTest> vet = new LinkedList <VelocityEstimateTest> ();
			VelocityEstimateTest tmpvet;
			for (Device d: fc.listOfDevices)
			{
				tmpvet = new VelocityEstimateTest(d);
				vet.add(tmpvet);				
			}

			for (int i = 0; i < CONSTANTS.nExample; i++) {
				int fileindex = randomGenerator.nextInt(_TESTDATA.size()) - 1;
				if (fileindex == -1) {
					fileindex = 0;
				}

				int start = randomGenerator.nextInt(_TESTDATA.get(fileindex).size() - sequence_length - 1);
				Sequence testdata = new Sequence();
				for (int j = start; j < start + sequence_length; j++) {
					testdata.add(new SequenceElement(_TESTDATA.get(fileindex).get(j)));
					testdata.getLast().Repetition = 1;
				}
	
				System.out.println("TEST " + (i + 1));
				out.write("TEST " + i + "\n");
				out.write("TESTDATA           :" + testdata.toString() + "\n");
				out.write("TEST REFINED1      :" + testdata.refineSequence().toString() + "\n");
				out.write("BUSROUTE           :" + _TESTDATA.get(fileindex).BusRouteID + "\n");
				
				//hide the state here
				testdata.BusRouteID = _TESTDATA.get(fileindex).BusRouteID;
				all = testSpeed(testdata.refineSequence(), out);
     
				
// HUNG UI. DOC CAI DONG NI
//VelocityEstimateTest t = new VelocityEstimateTest(cai device cua cai sequence o tren)
//t.returnVelocity(start, end);  
// cai start to end nay phai tinh relative to cai file 
//chu k phai tu 0 -> 300
// vi dzu testsequence o trong file bat dau tu 7
// thi phai tu 7 -> 307
                GPSv = vet.get(fileindex).returnVelocity(start + sequence_length - ESTI_LENGTH, start + sequence_length)*3600;
				out.write("GPS velocity:" + GPSv + "km/h\n"); 
                                

				
				
				int compare = testdata.getLast().State;
				for (int j = 0; j < testdata.sequenceinFile.size(); j++) {
					testdata.get(j).State = 0;
				}
				out.write("TEST REFINED2      :" + testdata.refineSequence().toString() + "\n");

				
				// find busstop
				System.out.println(sm.refined_seqs.size() +" " + testdata.refineSequence().toString());
				LinkedList<Character> result = sm.matchBusStop(testdata, out,CONSTANTS.ALLBUSROUTE);
				
				
				
				
				//VELOCITY ESTIMATE
				finalsteps = testVelocityEstimate(testdata, out, sm);
                                
                                out2.write(GPSv + "\t" + all + "\t" + finalsteps + "\t " + Math.abs(GPSv - all) + "\t" + Math.abs(GPSv - finalsteps) + "\n");
                                if (all > 0.000001)
                                {
                                SumDiffAll += Math.abs(GPSv - all);
                                allcount++;
                                if (Math.abs(GPSv - all) > allMax)
                                {
                                    allMax = Math.abs(GPSv - all);
                                }
                                if (Math.abs(GPSv - all) < allMin)
                                {
                                    allMin = Math.abs(GPSv - all);
                                }
                                }
                                if (finalsteps > 0.000001)
                                {
                                SumDiffSteps += Math.abs(GPSv - finalsteps);
                                stepcount++;
                                if (Math.abs(GPSv - finalsteps) > stepMax)
                                {
                                    stepMax = Math.abs(GPSv - finalsteps);
                                }
                                if (Math.abs(GPSv - finalsteps) < stepMin)
                                {
                                    stepMin = Math.abs(GPSv - finalsteps);
                                }
                                }
			}
			out.write("ALL MIN      :" + allMin + "\n");
                        out.write("ALL MAX      :" + allMax + "\n");
                        out.write("ALL AVG      :" + (SumDiffAll/allcount) + "\n");
                        out.write("STEP MIN      :" + stepMin + "\n");
                        out.write("STEP MAX      :" + stepMax + "\n");
                        out.write("STEP AVG      :" + (SumDiffSteps/stepcount) + "\n");
                        out2.write("ALL MIN      :" + allMin + "\n");
                        out2.write("ALL MAX      :" + allMax + "\n");
                        out2.write("ALL AVG      :" + (SumDiffAll/allcount) + "\n");
                        out2.write("STEP MIN      :" + stepMin + "\n");
                        out2.write("STEP MAX      :" + stepMax + "\n");
                        out2.write("STEP AVG      :" + (SumDiffSteps/stepcount) + "\n");
				out.close();
                                out2.close();

		} catch (Exception e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
		}

	}

	private double testSpeed(Sequence data, Writer out)
	{
		ve = new VelocityEstimate(busController);
                double result = 0;
		int timeStamp = 0;
		short[] interestedBusRoute = null;
		LinkedList<Character> interestedBustopID = new LinkedList<Character>();
		for (int i = 0; i < data.size(); i++) {
                        interestedBustopID.clear();
			interestedBustopID.add(data.get(i).State);
			interestedBusRoute = sm.possibleBusRoute(data.get(i).Observation);
			ve.Add(timeStamp, interestedBustopID, interestedBusRoute);
			timeStamp += data.get(i).Repetition;
		}
		
		ve.Add(timeStamp, interestedBustopID, interestedBusRoute);
		try {
                        result = ve.returnVelocity(data.score() - ESTI_LENGTH, data.score());
			if (result < 0.0000000001)
				System.out.println("?");
			out.write("VELOCITY: " + result + "km/s\n");
			out.write("VELOCITY: " + result * 3600 + "km/h\n");
			out.write("VELOCITY: " + result *1000 + "m/s\n");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
                return (result*3600);
	}
	
	private double testVelocityEstimate(Sequence sequence, Writer out, SequenceMatching sm) throws IOException
	{
		ve = new VelocityEstimate(busController);
		Sequence testsequence = new Sequence();
                double result = 0;
                int interval = 30;
		for (int i = 0; i < sequence.size(); ++i) {
			testsequence.sequenceinFile.addLast(sequence.get(i));

			if (i%interval!=(interval - 1))
				continue;
			out.write("TEST with: " + testsequence.size());
			
			short[] busroute = sm.possibleBusRoute(testsequence);
			int[] busroute2 = new int[busroute.length];
			for (int j = 0; j < busroute.length; j++) {
				busroute2[j]=busroute[j];
			}
			
			LinkedList<Character> busStops = new LinkedList<Character>();
			busStops = sm.matchBusStop(testsequence, out, busroute2);
			if (busStops==null || busStops.size() == 0)
				continue;
			
			ve.Add(i, busStops, busroute);
			try {
                result = ve.returnVelocity(i - ESTI_LENGTH, testsequence.score());
				out.write("VELOCITY: " + result + "km/s\n");
				out.write("VELOCITY: " + result*3600 + "km/h\n");
				out.write("VELOCITY: " + result*1000 + "m/s\n");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		out.write("END TEST \n\n\n\n\n");
                return (ve.returnVelocity(testsequence.score() - ESTI_LENGTH, testsequence.score())*3600);
	
	}
	
	private int findMode(Sequence sequence, int count) {
		// System.out.println("MAX");

		if (count > sequence.size())
			count = sequence.size();
		int maxCount = 0;
		int maxState = 0;
		char key = 0;
		int value = 0;
		Hashtable<Character, Integer> countBusStop = new Hashtable<Character, Integer>();
		for (int i = sequence.size() - count; i < sequence.size(); i++) {
			key = sequence.get(i).State;
			if (countBusStop.containsKey(key)) {
				value = countBusStop.get(key) + 1;
				countBusStop.put(key, value);
			} else {
				value = 1;
				countBusStop.put(key, value);
			}
			if (value > maxCount) {
				maxCount = value;
				maxState = key;
			}
		}

		return maxState;
	}
}
